treeview: Redo row tracking
authorBenjamin Otte <otte@redhat.com>
Sat, 12 Nov 2011 02:39:48 +0000 (03:39 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 16 Nov 2011 03:39:23 +0000 (04:39 +0100)
Track the RBNode/RBTree instead of keeping a TreeRowReference. This is a
whole lot faster and less error-prone.

Also, notify the accessible of removal of rows before actually removing
them, so we have a chance to clean up.

gtk/a11y/gtktreeviewaccessible.c
gtk/a11y/gtktreeviewaccessible.h
gtk/gtktreeview.c

index 92505ccd76677d8703366af8e87a69ed0d0005e7..d0798c3f201ba1c2ed0464df24a643b782e90b6d 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 #include "gtktreeprivate.h"
+#include "gtkwidgetprivate.h"
 
 #include "gtktreeviewaccessible.h"
 #include "gtkrenderercellaccessible.h"
@@ -38,7 +39,8 @@ typedef struct _GtkTreeViewAccessibleCellInfo  GtkTreeViewAccessibleCellInfo;
 struct _GtkTreeViewAccessibleCellInfo
 {
   GtkCellAccessible *cell;
-  GtkTreeRowReference *cell_row_ref;
+  GtkRBTree *tree;
+  GtkRBNode *node;
   GtkTreeViewColumn *cell_col_ref;
   GtkTreeViewAccessible *view;
 };
@@ -228,16 +230,15 @@ cell_info_free (GtkTreeViewAccessibleCellInfo *cell_info)
       _gtk_cell_accessible_add_state (cell_info->cell, ATK_STATE_DEFUNCT, FALSE);
     }
 
-  /* g_object_unref (cell_info->cell); */
-  if (cell_info->cell_row_ref)
-    gtk_tree_row_reference_free (cell_info->cell_row_ref);
   g_free (cell_info);
 }
 
 static GtkTreePath *
 cell_info_get_path (GtkTreeViewAccessibleCellInfo *cell_info)
 {
-  return gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  return _gtk_tree_view_find_path (NULL,
+                                   cell_info->tree,
+                                   cell_info->node);
 }
 
 static void
@@ -3079,7 +3080,16 @@ cell_info_new (GtkTreeViewAccessible *accessible,
   GtkTreeViewAccessibleCellInfo *cell_info;
 
   cell_info = g_new (GtkTreeViewAccessibleCellInfo, 1);
-  cell_info->cell_row_ref = gtk_tree_row_reference_new (tree_model, path);
+
+  if (!_gtk_tree_view_find_node (GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible))),
+                                path,
+                                 &cell_info->tree,
+                                 &cell_info->node))
+    {
+      /* This check needs to happen way earlier */
+      g_free (cell_info);
+      return;
+    }
 
   cell_info->cell_col_ref = tv_col;
   cell_info->cell = cell;
@@ -3504,3 +3514,63 @@ get_header_from_column (GtkTreeViewColumn *tv_col)
 
   return rc;
 }
+
+/**
+ * _gtk_rbtree_get_ancestor_node:
+ * @ancestor: the ancestor tree
+ * @child_tree: the potential child's tree
+ * @child_node: the potential child's node
+ *
+ * Finds the node that is the ancestor of @child_tree and @child_node
+ * and belongs to @ancestor. If @ancestor is not an ancestor tree
+ * of @child_node, %NULL is returned.
+ *
+ * Returns: the ancestor node or %NULL if @ancestor is not an ancestor.
+ **/
+static GtkRBNode *
+_gtk_rbtree_get_ancestor_node (GtkRBTree *ancestor,
+                               GtkRBTree *child_tree,
+                               GtkRBNode *child_node)
+{
+  while (child_tree != NULL)
+    {
+      if (child_tree == ancestor)
+        return child_node;
+
+      child_node = child_tree->parent_node;
+      child_tree = child_tree->parent_tree;
+    }
+
+  return NULL;
+}
+
+void
+_gtk_tree_view_accessible_remove (GtkTreeView *treeview,
+                                  GtkRBTree   *tree,
+                                  GtkRBNode   *node)
+{
+  GtkTreeViewAccessibleCellInfo *cell_info;
+  GHashTableIter iter;
+  GtkTreeViewAccessible *accessible;
+
+  accessible = GTK_TREE_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (treeview)));
+  if (accessible == NULL)
+    return;
+
+  /* if this shows up in profiles, special-case node->children == NULL */
+
+  g_hash_table_iter_init (&iter, accessible->cell_infos);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
+    {
+      GtkRBNode *child_node = _gtk_rbtree_get_ancestor_node (tree,
+                                                             cell_info->tree,
+                                                             cell_info->node);
+
+      if (child_node == NULL)
+        continue;
+
+      if (node == NULL || node == child_node)
+        g_hash_table_iter_remove (&iter);
+    }
+}
+
index c04a81615b031c0b9c7ab44221fb15d5c76884ff..e7de687cbf887781c2de131b3b9cfa022363a4e1 100644 (file)
@@ -21,6 +21,7 @@
 #define __GTK_TREE_VIEW_ACCESSIBLE_H__
 
 #include "gtkcontaineraccessible.h"
+#include "gtktreeprivate.h"
 
 G_BEGIN_DECLS
 
@@ -58,6 +59,11 @@ struct _GtkTreeViewAccessibleClass
 
 GType _gtk_tree_view_accessible_get_type (void);
 
+/* called by treeview code */
+void            _gtk_tree_view_accessible_remove        (GtkTreeView       *treeview,
+                                                         GtkRBTree         *tree,
+                                                         GtkRBNode         *node);
+
 G_END_DECLS
 
 #endif /* __GTK_TREE_VIEW_ACCESSIBLE_H__ */
index 62aec17201c9c85da150d6b5e06730dbe8cb82bc..2da21a655e4f6cb5ca478ea37801e8d16d105bd3 100644 (file)
@@ -9043,10 +9043,12 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
       if (tree_view->priv->tree == tree)
        tree_view->priv->tree = NULL;
 
+      _gtk_tree_view_accessible_remove (tree_view, tree, NULL);
       _gtk_rbtree_remove (tree);
     }
   else
     {
+      _gtk_tree_view_accessible_remove (tree_view, tree, node);
       _gtk_rbtree_remove_node (tree, node);
     }
 
@@ -12900,6 +12902,8 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
   tree_view->priv->last_button_x = -1;
   tree_view->priv->last_button_y = -1;
 
+  _gtk_tree_view_accessible_remove (tree_view, node->children, NULL);
+
   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
     {
       _gtk_rbtree_remove (node->children);